#pragma once

#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <atomic>
#include <fstream>
#include <boost/algorithm/string.hpp>
// #include "log.hpp"
namespace ns_util
{
    const std::string temp_path = "./temp/";
    class PathUtil
    {
    public:
        static std::string AddSuffix(const std::string &file_name,const std::string &suffix)
        {
            std::string path_name = temp_path;
            path_name += file_name + suffix;
            return path_name;
        }

        //构建源文件路径+文件名+后缀名:g++编译需要
        static std::string Src(const std::string &file_name)
        {
            return AddSuffix(file_name,".cpp");
        }
        //构建可执行程序的完整路径+文件名+后缀名
        static std::string Exe(const std::string &file_name)
        {
            return AddSuffix(file_name,".exe");
        }
        //构建该可执行程序编译时错误结果的完整路径+文件名+后缀名
        static std::string CompilerErr(const std::string &file_name)
        {
            return AddSuffix(file_name,".compile_err");
        }

        //可执行程序运行时需要的文件
        //可执行程序获得输入
        static std::string Stdin(const std::string &file_name)
        {
            return AddSuffix(file_name,".stdin");
        }

        //可执行程序输出正常结果
        static std::string Stdout(const std::string &file_name)
        {
            return AddSuffix(file_name,".stdout");
        }

        //可执行程序输出错误
        static std::string Stderr(const std::string &file_name)
        {
            return AddSuffix(file_name,".stderr");
        }

        //构建该可执行程序运行时错误结果的完整路径+文件名+后缀名
        static std::string RunErr(const std::string &file_name)
        {
            return AddSuffix(file_name,".run_err");
        }
    };

    class TimeUtil
    {
        public:
        static std::string GetTimeStamp()
        {
            struct timeval time;
            gettimeofday(&time,nullptr);
            return std::to_string(time.tv_sec);//返回累计到现在的秒数:时间戳
        }

        static std::string GetTimeMs()
        {
            struct timeval time;
            gettimeofday(&time,nullptr);
            return std::to_string(time.tv_sec * 1000 + time.tv_usec);//返回累计到现在的秒数:时间戳
        }
    };

    class FileUtil
    {
        public:
        static bool IsFileExists(const std::string &path_name)
        {
            //可以通过打开文件，判断文件是否存在
            //此处使用stat获取文件元数据的方式判断文件是否存在
            struct stat st;
            if(stat(path_name.c_str(),&st) == 0)
            {
                return true;
            }
            return false;
        }

        //利用毫秒级时间戳和原子性递增id生成唯一文件名    
        static std::string UniqueFileName()
        {
            static std::atomic_uint id(0);
            id++;
            std::string ms = TimeUtil::GetTimeMs();
            std::string uniq_id = std::to_string(id);
            return ms + "_" + uniq_id;
        }

        static bool WriteFile(const std::string &path_name,const std::string &code)
        {
            //将code内容写入path_name所对应的特定文件中
            std::ofstream out(path_name);
            if(!out.is_open())
                return false;
            out.write(code.c_str(),code.size());
            out.close();
            return true;
        }

        static std::string ReadFile(const std::string &path_name,bool keep = true)
        {
            //返回文件中错误信息
            std::ifstream in(path_name);
            if(!in.is_open())
                return "";//失败就返回空串
            //反复读取每行内容
            std::string line;
            std::string content;

            //返回本质是流对象：重载了operator bool
            while(std::getline(in,line))
            {
                content += line;
                content += keep ? "\n" : "";
            }
            in.close();
            return content;
        }
    };

    class StringUtil
    {
    public:
       /*********************************
        * str:输入的待切分的字符串
        * target：输出型参数，表示切分的结果
        * sep:切分所用的分隔符
        * ******************************/
        static void SplitString(const std::string &str,std::vector<std::string> &target,std::string sep)
        {
            //使用boost split
            boost::split(target,str,boost::is_any_of(sep),boost::algorithm::token_compress_on);
            //is_any_of(sep):sep中的任何一个字符均可作为分隔符
            //token_compress_on:如果两个分隔符中的内容为空，没有内容，则进行压缩，即不存在于最终的target中
        }
    };

    //IO的判题逻辑
    class JudgeUtil
    {
    public:
        static std::string Judge(std::string& output,std::string IO_Output,int& flag)
        {
            //如何进行比对
            std::string right_answer = FileUtil::ReadFile(IO_Output);
            std::string ret = "测试用例未全部通过";
            flag = 0;
            if(output == right_answer)
            {
                ret = "测试用例全部通过";
                flag = 1;
            }
            return ret;
        }
    };
}